/*******************************************************************************
 * \brief 需要256M内存，256M磁盘
 ******************************************************************************/
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "core.h"

/********************************** 宏定义 ***************************************/
#define FUNC_LIST_COUNT CELLS_TOTAL_COUNT

/********************************* 数据结构 **************************************/
typedef struct FUNC_LIST{
	int func_num;
	CELL_FUNC func;
} FUNC_LIST;

/********************************* 全局变量 **************************************/
static void cells_born(CELL *c);
static void cell_func1_input(void *self_cell, void *in, void *out);
static void cell_defalt_function(void *self_cell, void *in, void *out);
static void cell_func3_output(void *self_cell, void *in, void *out);
static void cell_func4_circle(void *self_cell, void *in, void *out);
static void cell_func5_circle(void *self_cell, void *in, void *out);
static void cell_func6_circle(void *self_cell, void *in, void *out);

// synapses: 突触
static SYNAPSES synapses[SYNAPSES_COUNT][SYNAPSES_COUNT][SYNAPSES_COUNT] = {0};
static GLOBAL_ENVIRONMENT evm;
static int energy = 0;

/* 与细胞序号匹配的蛋白质响应方法 */
static FUNC_LIST funcs[FUNC_LIST_COUNT] = {
	{.func_num = 0, .func = cell_func1_input},
	{.func_num = 1, .func = cell_defalt_function},
	{.func_num = 2, .func = cell_func3_output},
	{.func_num = 3, .func = cell_func4_circle},
	{.func_num = 4, .func = cell_func5_circle},
	{.func_num = 5, .func = cell_func6_circle}
};
CELL cells[CELLS_COUNT] = {0};

/********************************* 接口函数 **************************************/
void core_init(void)
{
	cells_born(cells);
}

void core_step(void)
{
	int i = 0;

	/**
	 * \brief 用一次潮汐遍历执行所有细胞函数
	 * \details 模拟个体的一次并行计算而细胞内所有蛋白质的操作就只能执行一次函数来
	 * 			近似模拟了，细胞之间的突触输入输出进行解耦，还可以用重复收到近似的信号
	 * 			来进行更高精度的模拟
	 */
tide:
	cells[i].cell_func(&cells[i], cells[i].param.sns_in[0], cells[i].param.sns_out[0]);
	i++;
	if (i >= CELLS_TOTAL_COUNT)
		goto exit;

	goto tide;

exit:
	return;
}

void core_exit(void)
{
	
}

/********************************* 底层函数 **************************************/

static void cells_born(CELL *c)
{
	/* 初始化所有突触 init all synapses */
	for (int i = 0; i < SYNAPSES_COUNT; i++) {
		for (int j = 0; j < SYNAPSES_COUNT; j++) {
			for (int k = 0; k < SYNAPSES_COUNT; k++) {
				synapses[i][j][k].x = i;
				synapses[i][j][k].y = j;
				synapses[i][j][k].z = k;
			}
		}
	}

	/* 初始化所有细胞 init all cells */
#define DEFALULT_SNS_COUNT 4
#define MONOPLAST_COUNT 3

	int i;
	for (i = 0; i < MONOPLAST_COUNT; i++) {
		c[i].cell_total = MONOPLAST_COUNT;
		c[i].func_num = funcs[i].func_num;
		c[i].cell_func = funcs[i].func;
		c[i].param.num = i;
		c[i].param.sns_in_count = DEFALULT_SNS_COUNT;
		c[i].param.sns_in[0] = &synapses[0][0][i*DEFALULT_SNS_COUNT];
		c[i].param.sns_in[1] = &synapses[0][0][i*DEFALULT_SNS_COUNT+1];
		c[i].param.sns_in[2] = &synapses[0][0][i*DEFALULT_SNS_COUNT+2];
		c[i].param.sns_in[3] = &synapses[0][0][i*DEFALULT_SNS_COUNT+3];
		c[i].param.sns_out_count = DEFALULT_SNS_COUNT;
		c[i].param.sns_out[0] = &synapses[0][0][i*DEFALULT_SNS_COUNT+4];
		c[i].param.sns_out[1] = &synapses[0][0][i*DEFALULT_SNS_COUNT+5];
		c[i].param.sns_out[2] = &synapses[0][0][i*DEFALULT_SNS_COUNT+6];
		c[i].param.sns_out[3] = &synapses[0][0][i*DEFALULT_SNS_COUNT+7];
	}

	for (i = MONOPLAST_COUNT; i < CELLS_TOTAL_COUNT; i++) {
		c[i].cell_total = CELLS_TOTAL_COUNT;
		c[i].func_num = funcs[i].func_num;
		c[i].cell_func = funcs[i].func;
		c[i].param.num = i;
		c[i].param.sns_in_count = DEFALULT_SNS_COUNT;
		c[i].param.sns_in[0] = &synapses[0][0][i*DEFALULT_SNS_COUNT];
		c[i].param.sns_in[1] = &synapses[0][0][i*DEFALULT_SNS_COUNT+1];
		c[i].param.sns_in[2] = &synapses[0][0][i*DEFALULT_SNS_COUNT+2];
		c[i].param.sns_in[3] = &synapses[0][0][i*DEFALULT_SNS_COUNT+3];
		c[i].param.sns_out_count = DEFALULT_SNS_COUNT;
		c[i].param.sns_out[0] = &synapses[0][0][i*DEFALULT_SNS_COUNT+4];
		c[i].param.sns_out[1] = &synapses[0][0][i*DEFALULT_SNS_COUNT+5];
		c[i].param.sns_out[2] = &synapses[0][0][i*DEFALULT_SNS_COUNT+6];
		c[i].param.sns_out[3] = &synapses[0][0][i*DEFALULT_SNS_COUNT+7];
	}
	/* make circle */
	c[i-1].param.sns_out[0] = &synapses[0][0][MONOPLAST_COUNT*DEFALULT_SNS_COUNT];
	c[i-1].param.sns_out[1] = &synapses[0][0][MONOPLAST_COUNT*DEFALULT_SNS_COUNT+1];
	c[i-1].param.sns_out[2] = &synapses[0][0][MONOPLAST_COUNT*DEFALULT_SNS_COUNT+2];
	c[i-1].param.sns_out[3] = &synapses[0][0][MONOPLAST_COUNT*DEFALULT_SNS_COUNT+3];
}

static void cell_defalt_function(void *self_cell, void *in, void *out)
{
	CELL *self = (CELL *)self_cell; // use for modify function
	SYNAPSES *sns_in = (SYNAPSES *)in;
	SYNAPSES *sns_out = (SYNAPSES *)out;

	/* 数据输入到输出直接路由 copy data from input to output */
	for (int i = 0; i < self->param.sns_out_count; i++) {
		self->param.sns_out[i]->transmission = self->param.sns_in[i]->transmission;
	}
}

// 参数信息 params info:
// cells[0].param.sns_in_count = 4;
// cells[0].param.sns_in[0]->transmission = body->direction;
// cells[0].param.sns_in[1]->transmission = body->energy;
// cells[0].param.sns_in[2]->transmission = body->data_near;
// cells[0].param.sns_in[3]->transmission = body->data_far;
static void cell_func1_input(void *self_cell, void *in, void *out)
{
	CELL *self = (CELL *)self_cell; // use for modify function

	DIRECTION peek_direction = (DIRECTION)self->param.sns_in[0]->transmission;
	int energy = self->param.sns_in[1]->transmission;
	TYPE data_near = (TYPE)self->param.sns_in[2]->transmission;
	TYPE data_far = (TYPE)self->param.sns_in[3]->transmission;
	DIRECTION move = MOTIONLESS;

	if (energy < ORIGIN_ENERGY / 2) {
		/* hunger */
		if (data_near == FOOD || data_far == FOOD) {
			move = peek_direction;
			self->param.sns_out[0]->transmission = move;
			self->param.sns_out[1]->transmission = peek_direction;
		} else {
#define LIMIT (RIGHT + 1)
			struct timespec cur_time = {0, 0};
			clock_gettime(CLOCK_REALTIME, &cur_time);
			srand((unsigned int )cur_time.tv_nsec);
			int i = rand();
			i %= LIMIT;

			peek_direction = i;

			self->param.sns_out[0]->transmission = peek_direction;
			self->param.sns_out[1]->transmission = peek_direction;
		}
	} else {
		/* glut */
		if (data_near == NONE) {
			move = peek_direction;
			self->param.sns_out[0]->transmission = move;
			self->param.sns_out[1]->transmission = peek_direction;
		} else {
			self->param.sns_out[0]->transmission = move;
			peek_direction++;
			if (peek_direction > RIGHT)
				peek_direction = TOP;
			self->param.sns_out[1]->transmission = peek_direction;
		}
	}
}

// 参数信息 params info:
// int move_drt = cells[CELLS_TOTAL_COUNT - 1].param.sns_out[0]->transmission; // move direction(or not move)
// int peep_drt = cells[CELLS_TOTAL_COUNT - 1].param.sns_out[1]->transmission; // peep direction
static void cell_func3_output(void *self_cell, void *in, void *out)
{
	CELL *self = (CELL *)self_cell; // use for modify function

	for (int i = 0; i < self->param.sns_out_count; i++) {
		self->param.sns_out[i]->transmission = self->param.sns_in[i]->transmission;
	}
}

static void cell_func4_circle(void *self_cell, void *in, void *out)
{
	CELL *self = (CELL *)self_cell;

	for (int i = 0; i < self->param.sns_out_count; i++) {
		self->param.sns_out[i]->transmission = self->param.sns_in[i]->transmission;
	}
}

static void cell_func5_circle(void *self_cell, void *in, void *out)
{
	CELL *self = (CELL *)self_cell;

	for (int i = 0; i < self->param.sns_out_count; i++) {
		self->param.sns_out[i]->transmission = self->param.sns_in[i]->transmission;
	}
}

static void cell_func6_circle(void *self_cell, void *in, void *out)
{
	CELL *self = (CELL *)self_cell;

	for (int i = 0; i < self->param.sns_out_count; i++) {
		self->param.sns_out[i]->transmission = self->param.sns_in[i]->transmission;
	}
}